package com.timothy.remote.client;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Filter;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.timothy.remote.core.RemoteServiceInterface;

@Configuration
@EnableConfigurationProperties({ ClientShiroProperties.class })
public class ClientShiroConfig {

	@Bean(name = "remoteService")
	public RemoteServiceInterface remoteService(ClientShiroProperties clientShiroProperties) {
		HttpInvokerProxyFactoryBean remoteService = new HttpInvokerProxyFactoryBean();
		remoteService.setServiceUrl(clientShiroProperties.getRemoteServiceUrl());
		remoteService.setServiceInterface(RemoteServiceInterface.class);
		remoteService.afterPropertiesSet();
		return (RemoteServiceInterface) remoteService.getObject();
	}

	/**
	 * redis管理
	 * @param redisProperties
	 * @return
	 */
	@Bean
	public RedisManager redisManager(RedisProperties redisProperties) {
		RedisManager redisManager = new RedisManager();
		redisManager.setHost(redisProperties.getHost());
		redisManager.setPort(redisProperties.getPort());
		redisManager.setDatabase(redisProperties.getDatabase());
		redisManager.setPassword(redisProperties.getPassword());
		return redisManager;
	}

	// @Bean
	// public ClientSessionDAO clientSessionDAO(RemoteServiceInterface remoteService) {
	// ClientSessionDAO clientSessionDAO = new ClientSessionDAO();
	// clientSessionDAO.setSessionIdGenerator(new JavaUuidSessionIdGenerator());
	// clientSessionDAO.setRemoteService(remoteService);
	// return clientSessionDAO;
	// }

	/**
	 * 基于redis的session dao
	 * @param redisManager
	 * @param shiroProperties
	 * @return
	 */
	@Bean
	public RedisSessionDAO redisSessionDAO(RedisManager redisManager, ClientShiroProperties shiroProperties) {
		RedisSessionDAO redisSessionDao = new RedisSessionDAO();
		redisSessionDao.setRedisManager(redisManager);
		redisSessionDao.setExpire(shiroProperties.getRedisSessionExpire());
		redisSessionDao.setKeyPrefix(shiroProperties.getRedisSessionPrefix());
		return redisSessionDao;
	}

	/**
	 * session id的cookie
	 * @return
	 */
	@Bean
	public SimpleCookie sessionIdCookie() {
		SimpleCookie simpleCookie = new SimpleCookie("sid");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(-1);
		simpleCookie.setDomain("");
		simpleCookie.setPath("");
		return simpleCookie;
	}

	/**
	 * session 管理
	 * @param sessionDAO
	 * @param sessionIdCookie
	 * @param clientShiroProperties
	 * @return
	 */
	@Bean
	public DefaultWebSessionManager sessionManager(AbstractSessionDAO sessionDAO, SimpleCookie sessionIdCookie,
			ClientShiroProperties clientShiroProperties) {
		DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
		defaultWebSessionManager.setGlobalSessionTimeout(clientShiroProperties.getRedisSessionExpire() * 1000);
		defaultWebSessionManager.setDeleteInvalidSessions(false);
		defaultWebSessionManager.setSessionValidationSchedulerEnabled(false);
		defaultWebSessionManager.setSessionIdCookieEnabled(true);
		defaultWebSessionManager.setSessionDAO(sessionDAO);
		defaultWebSessionManager.setSessionIdCookie(sessionIdCookie);
		return defaultWebSessionManager;
	}

	/**
	 * cache管理
	 * @param redisManager
	 * @return
	 */
	@Bean(name = "cacheManager")
	public CacheManager cacheManager(RedisManager redisManager, ClientShiroProperties shiroProperties) {
		RedisCacheManager redisCacheManager = new RedisCacheManager();
		redisCacheManager.setRedisManager(redisManager);
		redisCacheManager.setKeyPrefix(shiroProperties.getRedisCachePrefix());
		// 过期时间，秒值
		redisCacheManager.setExpire(shiroProperties.getRedisCacheExpire());
		return redisCacheManager;
	}

	// 安全管理器
	@Bean(name = "securityManager")
	public DefaultWebSecurityManager securityManager(ClientShiroRealm remoteRealm, SessionManager sessionManager,
			CacheManager cacheManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(remoteRealm);
		securityManager.setSessionManager(sessionManager);
		securityManager.setCacheManager(cacheManager);
		// securityManager.setRememberMeManager(cookieRememberMeManager());
		return securityManager;
	}

	@Bean
	public MethodInvokingFactoryBean methodInvokingFactoryBean(SecurityManager securityManager) {
		MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
		factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
		factoryBean.setArguments(securityManager);
		return factoryBean;
	}

	@Bean(name = "shiroFilter")
	public ClientShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
			ClientShiroProperties clientShiroProperties) {
		ClientShiroFilterFactoryBean shiroFilterFactoryBean = new ClientShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		shiroFilterFactoryBean.setLoginUrl(clientShiroProperties.getLoginUrl());
		shiroFilterFactoryBean.setSuccessUrl(clientShiroProperties.getLoginSuccessUrl());
		shiroFilterFactoryBean.setUnauthorizedUrl(clientShiroProperties.getUnauthorizedUrl());
		Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
		// filters.put("cas", casFilter());
		// filters.put("authc", clientAuthenticationFilter);
		shiroFilterFactoryBean.setFilters(filters);
		shiroFilterFactoryBean.setFiltersStr(clientShiroProperties.getFiltersStr());
		shiroFilterFactoryBean.setFilterChainDefinitionMap(clientShiroProperties.getFilterChainDefinitions());
		return shiroFilterFactoryBean;
	}

	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
		proxyCreator.setProxyTargetClass(true);
		return proxyCreator;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager);
		return advisor;
	}

	// @Bean
	// public SimpleMappingExceptionResolver simpleMappingExceptionResolver(ClientShiroProperties clientShiroProperties)
	// {
	// SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
	// Properties prop1 = new Properties();
	// prop1.setProperty("org.apache.shiro.authz.UnauthorizedException", clientShiroProperties.getLoginUrl());
	// prop1.setProperty("org.apache.shiro.authz.UnauthenticatedException", clientShiroProperties.getLoginUrl());
	// exceptionResolver.setExceptionMappings(prop1);
	// return exceptionResolver;
	// }
}
